﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace GSE
{
    public class Logger
    {
        protected static ILogger defaultLogger;
        public static void Init(ILogger defaultLogger)
        {
            Logger.defaultLogger = defaultLogger;
        }

        public static ILogger Default
        {
            get
            {
                if (defaultLogger == null)
                {
                    defaultLogger = new GSELogger(LogLevel.DEBUG);
                }
                return defaultLogger;
            }
        }

    }
    public interface ILogger
    {
        void Debug(string message);
        void Warn(string message);
        void Error(string message);
        void Fatal(string message);
        void Info(string message);
    }
    public enum LogLevel
    {
        DEBUG,
        INFO,
        WARN,
        ERROR,
        FATAL
    }

    public class GSELogger : ILogger
    {
        protected LogLevel level;
        public GSELogger()
        {
            level = LogLevel.INFO;
        }

        protected Dictionary<LogLevel, string> lvlStrings = new Dictionary<LogLevel, string>();

        public GSELogger(LogLevel level)
        {
            this.level = level;
            lvlStrings.Add(LogLevel.DEBUG, "DEBUG");
            lvlStrings.Add(LogLevel.INFO, "INFO");
            lvlStrings.Add(LogLevel.WARN, "WARN");
            lvlStrings.Add(LogLevel.ERROR, "ERROR");
            lvlStrings.Add(LogLevel.FATAL, "FATAL");

        }

        public string LevelToString(LogLevel lvl)
        {
            return lvlStrings[lvl];
        }
        protected string getTrace()
        {
            var frame = new StackTrace(3, true).GetFrame(0);
            return $"{frame.GetFileName()}({frame.GetFileLineNumber()},{frame.GetFileColumnNumber()})";
        }
        protected string format(string message, LogLevel lvl)
        {
            var d = DateTime.Now;
            if (level == LogLevel.DEBUG)
            {
                return "[" + LevelToString(lvl) + "]" + " " + d.ToUniversalTime().ToLongDateString() + " " + d.ToLongTimeString() + getTrace() + " " + message;
            }
            return "[" + LevelToString(lvl) + "]" + " " + d.ToUniversalTime().ToLongDateString() + " " + d.ToLongTimeString() + " " + message;
        }
        public void Debug(string message)
        {
            if (level > LogLevel.DEBUG)
            {
                return;
            }
            Console.WriteLine(format(message, LogLevel.DEBUG));
        }

        public void Info(string message)
        {
            if (level > LogLevel.INFO)
            {
                return;
            }
            Console.WriteLine(format(message, LogLevel.INFO));
        }

        public void Warn(string message)
        {
            if (level > LogLevel.WARN)
            {
                return;
            }
            Console.WriteLine(format(message, LogLevel.WARN));
        }

        public void Error(string message)
        {
            if (level > LogLevel.ERROR)
            {
                return;
            }
            Console.WriteLine(format(message, LogLevel.ERROR));
        }

        public void Fatal(string message)
        {
            if (level > LogLevel.FATAL)
            {
                return;
            }
            Console.WriteLine(format(message, LogLevel.FATAL));
        }
    }
}
